

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "securec.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#include "ohos_types.h"
#include "FreeRTOS.h"
#include "wifi_task.h"
#include "tcpip_adapter.h"
#include "wifi_ap/wifi_ap.h"
#include "wifi_sta/wifi_sta.h"
#include "nvs_netconfig/nvs_netconfig.h"
// #include "http_netconfig/http_netconfig.h"
#include "ping_func/ping_func.h"
#include "lwip/inet.h"
#include "utils_log.h"

static osThreadId_t g_tid = NULL;

#define POLL_TIMEOUT_TICS    pdMS_TO_TICKS(1000)

#define MAX_WIFI_SSID_LEN   32
#define MAX_WIFI_PSW_LEN    64
#define MIN_WIFI_PSW_LEN    8
#define MAX_RETRY_COUNT     60 
#define MAX_PING_INTERVAL   1800    //ping间隔

void SetWifiStaticIpConfig()
{
    tcpip_adapter_ip_info_t ipInfo;
    memset(&ipInfo, 0, sizeof(tcpip_adapter_ip_info_t));
    int ret = GetNvsWifiIpconfig(&ipInfo, sizeof(tcpip_adapter_ip_info_t));
    if (ret != ESP_OK) {
        tcpip_adapter_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
        tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_STA, &status);
        if (ESP_NETIF_DHCP_STOPPED == status){
            tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
        }
    } else {
        tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
        ret = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo);
        if (ret != ESP_OK){
            tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
        }
    }
}

//执行ping命令确认网络连通性是否良好，出现故障则重启系统
void ExecWifiPingCmd()
{
    //获取默认网关地址
    tcpip_adapter_ip_info_t ipInfo;
    tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo);

    //执行ping命令
    PingConfig_t config;
    memset(&config, 0, sizeof(config));
    printf( "[%s-%d]gateway is %s\r\n", __func__, __LINE__, inet_ntoa(ipInfo.gw));
    memcpy(config.targetAddr, inet_ntoa(ipInfo.gw), sizeof(config.targetAddr));
    int ret = ExecPingCmd(&config);
    if (ret != 0) {
        return;
    }

    ret = GetNetworkConnectivityResult();
    if(ret == NETWORK_CONNECTIVITY_FAIL){
        esp_restart();
    }
}

void WifiTask(void)
{
    bool setFlag = false;
    //1.首先获取wifi名称与密码
    char ssid[MAX_WIFI_SSID_LEN]={0}, psw[MAX_WIFI_PSW_LEN] = {0};
    GetNvsWifiSsid(ssid, sizeof(ssid));
    GetNvsWifiPsw(psw, sizeof(psw));
    printf( "[%s-%d]-ssid=%s, psw=%s\r\n", __func__, __LINE__, ssid, psw);

    //2.判断WiFi名称与密码长度
    if((strlen(ssid)>0) && (strlen(psw)>=MIN_WIFI_PSW_LEN)){ //已有配网信息,则开始连接WiFi
        printf( "[%s-%d] connect to AP\r\n", __func__, __LINE__);
        setFlag = true;
        ConnectToAP(ssid, psw);
        SetWifiStaticIpConfig();
    }

    int statusFlag = 0;
    int saveFlag = GetNvsWifiConnectStatus(&statusFlag, sizeof(statusFlag)); 
    int ret = 0;
    int retryCount = 0;
    uint32_t pingInterval = 0;
    uint32_t tryConnectBestCount = 0;
    while (1){
        if (setFlag) {  //已有WiFi sta参数情况下 
            pingInterval++;
            if (pingInterval == MAX_PING_INTERVAL){ //间隔30分钟执行ping命令
                pingInterval = 0;
                ExecWifiPingCmd();
            }

            tryConnectBestCount++;
            if(MAX_RETRY_COUNT == tryConnectBestCount){  //60s进行一次最佳WiFi判定
                ConnectBestWifi(ssid, psw);
                tryConnectBestCount = 0;
            }
            
            if(IsWifiConnect()){    //判断WiFi连接成功
                if (saveFlag != 0){     //未存储情况下进行存储一次
                    statusFlag = WIFI_STATE_CONNECTED;
                    SetNvsWifiConnectStatus(&statusFlag, sizeof(statusFlag));
                }//
                osDelay(POLL_TIMEOUT_TICS);
                continue;
            }
            
            //尝试重连 60s, 重连失败且从未连接成功则需重新进入AP模式
            retryCount++;
            if(MAX_RETRY_COUNT==retryCount && (statusFlag!=WIFI_STATE_CONNECTED)){
                setFlag = false;
                retryCount = 0;
            }
            
            if (retryCount == (MAX_RETRY_COUNT*3)){ //重连3分钟失败，则重启系统
                retryCount = 0;
                esp_restart();
            }   
        } else {
            if(!IsHotspotStateAvailable()){
                SetNetconfigFlag(WIFI_NETCONFIG_INIT);
                DisconnectWifi();
                osDelay(POLL_TIMEOUT_TICS);
                StartWifiAP();
            }
            
            if(GetNetconfigFlag() != WIFI_NETCONFIG_SUCCEED){
                osDelay(POLL_TIMEOUT_TICS);
                continue;
            }

            //配网成功标志,重新获取WiFi名称与密码
            GetNvsWifiSsid(ssid, sizeof(ssid));
            GetNvsWifiPsw(psw, sizeof(psw));
            printf( "[%s-%d]-ssid=%s, psw=%s\r\n", __func__, __LINE__, ssid, psw);
            if(strlen(ssid)>0 && strlen(psw)>=MIN_WIFI_PSW_LEN){ //已有配网信息,则开始连接WiFi
                StopWifiAP();
                osDelay(POLL_TIMEOUT_TICS*3);    
                setFlag = true;
                ConnectToAP(ssid, psw);
                SetWifiStaticIpConfig();
            } 
        }
        osDelay(POLL_TIMEOUT_TICS);
    }
}

int StartWifiTask(void)
{
    osThreadAttr_t attr;
    attr.name = "WIFI_TASK";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 0x2000;
    attr.priority = 25;

    g_tid = osThreadNew((osThreadFunc_t)WifiTask, NULL, &attr);
    if (g_tid == NULL) {
        printf("Failed to create wifi task!\n");
        LOG_TO_FILE("Failed to create wifi task!");
        return -1;
    }
    return 0;
}

void StopWifiTask(void)
{
    if (NULL == g_tid) {
        return;
    }

    osThreadTerminate(g_tid);
    g_tid = NULL;
}

bool IsWifiAvailable()
{
    if(IsHotspotStateAvailable() || IsWifiConnect()){
        return true;
    }

    return false;
}